﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using Foundation.ExtensionMethods;

namespace Foundation.MarkupExtensions
{
    public class MenuGenerator : MarkupExtension
    {
        public string SourceName { get; set; }
        public string SourcePropertyName { get; set; }
        public string StyleStaticKey { get; set; }

        protected readonly ObservableCollection<FrameworkElement> Items = new ObservableCollection<FrameworkElement>();
        protected FrameworkElement TargetObject;
        protected FrameworkElement SourceObject;
        protected Style ItemContainerStyle { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var service = (IProvideValueTarget) serviceProvider.GetService(typeof (IProvideValueTarget));
            TargetObject = service.TargetObject as FrameworkElement;
            if (TargetObject == null) return this;
            TargetObject.Loaded += OnLoaded;
            var menuItem = TargetObject as MenuItem;
            if (menuItem != null) menuItem.SubmenuOpened += OnOpening;
            var contextMenu = TargetObject as ContextMenu;
            if (contextMenu != null) contextMenu.Opened += OnOpening;
            return Items;
        }

        private void OnLoaded(object sender, RoutedEventArgs args)
        {
            var placement = sender as DependencyObject;
            var contextMenu = TargetObject as ContextMenu;
            if (contextMenu != null)
                placement = contextMenu.PlacementTarget;

            var menuItem = TargetObject as MenuItem;
            if (menuItem != null)
                placement = menuItem.GetRootMenuPlacement();

            var window = placement is ContentControl ? (ContentControl)placement : placement.GetNearestVisualAncestor<ContentControl>();
            var ancestors = placement.GetVisualAncestors<FrameworkElement>();
            ancestors.Insert(0, placement as FrameworkElement);
            SourceObject = ancestors.FirstOrDefault(a => a.Name == SourceName);
            if (SourceObject == null)
            {
                if (window == null) return;
                var descendants = window.GetVisualDescendants<FrameworkElement>();
                descendants.Insert(0, window);
                SourceObject = descendants.FirstOrDefault(c => c.Name == SourceName);
                if (SourceObject == null) return;
            }

            do
            {
                ItemContainerStyle =
                    string.IsNullOrEmpty(StyleStaticKey)
                        ? null
                        : (Style) window.Resources[StyleStaticKey];
                window = window.GetNearestVisualAncestor<ContentControl>();
            } while (window != null && ItemContainerStyle == null);
            
            var items = GenerateMenu();
            Items.AddRange(items);

            Localizing.LocalizationChanged += () =>
                {
                    Items.Clear();
                    items = GenerateMenu();
                    Items.AddRange(items);
                };

            TargetObject.Loaded -= OnLoaded;
        }

        protected virtual void OnOpening(object sender, RoutedEventArgs routedEventArgs)
        {
        }

        protected virtual ICollection<FrameworkElement> GenerateMenu()
        {
            return new ObservableCollection<FrameworkElement>();
        }
    }
}
